package com.sunmouse.toolkit.widget;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;

import com.sunmouse.toollib.utils.LogUtils;
import com.sunmouse.toollib.utils.StringUtils;
import com.sunmouse.toolkit.util.Constants;

/**
 * Created by Administrator on 2017/10/12 0012.
 */
public class PieView extends View {
    public static final String TAG = PieView.class.getSimpleName();
    private GestureDetector mDetector;
    private Paint arcPaint;
    private Paint legendPaint;


    private RectF mRect;

    private float[] scales;
    private float radius;
    private int thickness;
    private int selectedArea;
    private float textSize;

    private Point center;

    /**
     * click valid area
     */
    private float validL;
    private float validT;
    private float validR;
    private float validB;

    /**
     * line length related
     */
    private float stretchX;
    private float stretchY;
    private float straightX;


    public PieView(Context context) {
        this(context, null);
    }

    public PieView(Context context, AttributeSet attrs) {
        super(context, attrs);
        DisplayMetrics metrics = getResources().getDisplayMetrics();
        textSize = (11 * metrics.density);
        arcPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
        legendPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        legendPaint.setColor(Color.BLACK);
        legendPaint.setStrokeWidth(1.0f);
        legendPaint.setTextSize(textSize);
        legendPaint.setTextAlign(Paint.Align.CENTER);

        mRect = new RectF();

        scales = getSlices(7);
        thickness = 22;
        this.selectedArea = -1;

        stretchX = 0.2f;
        stretchY = 0.1f;
        straightX = 0.35f;

        mDetector = new GestureDetector(getContext(), new PieGestureHandler());
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        radius = (float) (getMeasuredWidth() / 2 * 0.7);
        validL = (getMeasuredWidth() / 2 - radius);
        validT = (getMeasuredHeight() / 2 - radius);
        validR = (getMeasuredWidth() / 2 + radius);
        validB = (getMeasuredWidth() / 2 + radius);

        //store pie center
        setCenter(getMeasuredWidth() / 2, getMeasuredHeight() / 2);

        LogUtils.v(TAG, "--------------canvasX=" + getX() + "---canvasY=" + getY());
    }

    /**
     * set center point
     *
     * @param x
     * @param y
     */
    private void setCenter(int x, int y) {
        if (center == null) {
            center = new Point(x, y);
            return;
        }
        center.setX(x);
        center.setY(y);
    }

    /**
     * draw Arc: in clockwise   {0du for xAxis 90du for yAxis and so on}
     *
     * @param canvas
     */
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        LogUtils.v(TAG, "----------canvasW=" + canvas.getWidth() + "--canvasH=" + canvas.getHeight());
        for (int j = 0; j < thickness; j++) {
            float startAngle = 0;
            float sweepAngle = 0;
            for (int i = 0; i < scales.length; i++) {
                mRect.left = getWidth() / 2 - radius;
                mRect.top = getHeight() / 2 - radius - j;
                mRect.right = mRect.left + 2 * radius;
                mRect.bottom = mRect.top + 2 * radius - j;
                arcPaint.setColor(Constants.ShaderColors[i]);
                sweepAngle = 360 * scales[i];
                if (i == selectedArea) scaleRectF(0.1f);
                canvas.drawArc(mRect, startAngle, sweepAngle, true, arcPaint);
                startAngle += sweepAngle;
            }
        }

        float startAngle = 0;
        float sweepAngle = 0;
        for (int i = 0; i < scales.length; i++) {
            mRect.left = getWidth() / 2 - radius;
            mRect.top = getHeight() / 2 - radius - thickness;
            mRect.right = mRect.left + 2 * radius;
            mRect.bottom = mRect.top + 2 * radius - thickness;
            arcPaint.setColor(Constants.Colors[i]);
            sweepAngle = 360 * scales[i];
            if (i == selectedArea) scaleRectF(0.1f);
            canvas.drawArc(mRect, startAngle, sweepAngle, true, arcPaint);
            drawLegend(canvas, startAngle, scales[i]);
            startAngle += sweepAngle;
        }

    }

    /**
     * draw legend
     *
     * @param canvas
     * @param startAngle
     * @param scales
     */
    private void drawLegend(Canvas canvas, float startAngle, float scales) {
        float legendAngle = startAngle + scales * 360 / 2;
        double legendRadian = Math.toRadians(legendAngle);
        float sx = center.getX() + (float) (radius * Math.cos(legendRadian) * 0.8f);
        float sy = center.getY() + (float) (radius * Math.sin(legendRadian) * 0.8f);
        if (0 < legendAngle && legendAngle < 90) {//down right
            canvas.drawCircle(sx, sy, 10, legendPaint);
            canvas.drawLine(sx, sy, sx + stretchX * radius, sy + stretchY * radius, legendPaint);
            canvas.drawLine(sx + stretchX * radius, sy + stretchY * radius, sx + stretchX * radius + straightX * radius, sy + stretchY * radius, legendPaint);
            canvas.drawText(StringUtils.toPercent(scales), sx + stretchX * radius + straightX * radius, sy + stretchY * radius, legendPaint);
        } else if (90 < legendAngle && legendAngle < 180) {//down left
            canvas.drawCircle(sx, sy, 10, legendPaint);
            canvas.drawLine(sx, sy, sx - stretchX * radius, sy + stretchY * radius, legendPaint);
            canvas.drawLine(sx - stretchX * radius, sy + stretchY * radius, sx - stretchX * radius - straightX * radius, sy + stretchY * radius, legendPaint);
            canvas.drawText(StringUtils.toPercent(scales), sx - stretchX * radius - straightX * radius - 20, sy + stretchY * radius, legendPaint);
        } else if (180 < legendAngle && legendAngle < 270) {//up left
            canvas.drawCircle(sx, sy, 10, legendPaint);
            canvas.drawLine(sx, sy, sx - stretchX * radius, sy - stretchY * radius, legendPaint);
            canvas.drawLine(sx - stretchX * radius, sy - stretchY * radius, sx - stretchX * radius - straightX * radius, sy - stretchY * radius, legendPaint);
            canvas.drawText(StringUtils.toPercent(scales), sx - stretchX * radius - straightX * radius - 20, sy - stretchY * radius, legendPaint);
        } else if (270 < legendAngle && legendAngle < 360) { //up right
            canvas.drawCircle(sx, sy, 10, legendPaint);
            canvas.drawLine(sx, sy, sx + stretchX * radius, sy - stretchY * radius, legendPaint);
            canvas.drawLine(sx + stretchX * radius, sy - stretchY * radius, sx + stretchX * radius + straightX * radius, sy - stretchY * radius, legendPaint);
            canvas.drawText(StringUtils.toPercent(scales), sx + stretchX * radius + straightX * radius, sy - stretchY * radius, legendPaint);
        }
    }

    /**
     * scale rect
     *
     * @param scale
     */
    private void scaleRectF(float scale) {
        mRect.left -= radius * scale;
        mRect.top -= radius * scale;
        mRect.right += radius * scale;
        mRect.bottom += radius * scale;
    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
//        LogUtils.v(TAG, "-------------------touch");
        return mDetector.onTouchEvent(event);
    }

    /**
     * generate random scales
     *
     * @return
     */
    public float[] getRandomScales(int length) {
        float[] scales = new float[length];
        float total = 0.0f;
        for (int i = 0; i < length - 1; i++) {
            float temp = (float) Math.random() / length;
            scales[i] = temp;
            total += temp;
        }
        scales[length - 1] = 1 - total;
        return scales;

    }

    /**
     * generate random slices
     *
     * @return
     */
    public float[] getSlices(int len) {
        float[] points = new float[len];
        float remain = 1.0f;
        for (int i = 0; i < points.length; i++) {
            if (i == points.length - 1) {
                points[i] = remain;
//                LogUtils.v("------slice-----" + points[i]);
                return points;
            }
            points[i] = (float) (Math.random() / 2) * remain;
//            LogUtils.v("------slice-----" + points[i]);
            remain -= points[i];
        }
        return points;
    }


    /**
     * pie gesture listener
     */
    private class PieGestureHandler implements GestureDetector.OnGestureListener {
        @Override
        public boolean onDown(MotionEvent e) {
//            LogUtils.v(TAG, "-----------onDown------");
            return true;//set to true for invoking onSingleTapUp
        }

        @Override
        public void onShowPress(MotionEvent e) {
//            LogUtils.v(TAG, "-----------onShowPress------");

        }

        @Override
        public boolean onSingleTapUp(MotionEvent e) {
            LogUtils.v(TAG, "-----------onSingleTapUp------");
            switch (e.getAction()) {
                case MotionEvent.ACTION_UP:
                    selectedArea = findArea(e);
                    LogUtils.v(TAG, "-----------ACTION_UP------" + selectedArea);
                    invalidate();
                    break;
                case MotionEvent.ACTION_DOWN:
                    selectedArea = findArea(e);
                    break;
            }
            return true;
        }

        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
//            LogUtils.v(TAG, "-----------onScroll------");
            return false;
        }

        @Override
        public void onLongPress(MotionEvent e) {
//            LogUtils.v(TAG, "-----------onLongPress------");

        }

        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
//            LogUtils.v(TAG, "-----------onFling------");
            return false;
        }
    }

    /**
     * find area in which Arc
     *
     * @param e
     * @return
     */
    private int findArea(MotionEvent e) {
        float x = e.getX();
        float y = e.getY();
        LogUtils.v(TAG, "--------------x=" + x + "---y=" + y);

        //click invalid area
        if (x < validL || x > validR) return -1;
        if (y < validT || x > validB) return -1;

        //calculate click area
        float deltaX = x - center.getX();
        float deltaY = y - center.getY();

        double distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
        double asin = Math.asin(deltaY / distance);
        float degree = (float) Math.toDegrees(asin);
        if (deltaX > 0 && deltaY > 0) {//forth quadrant
        } else if (deltaX < 0 && deltaY > 0) {//third quadrant
            degree = 180 - degree;
        } else if (deltaX < 0 && deltaY < 0) {//second quadrant
            degree = 180 - degree;
        } else if (deltaX > 0 && deltaY < 0) {//first quadrant
            degree = 360 + degree;
        }
        LogUtils.v(TAG, "----------------degree=" + degree);
        return calculateArea(degree);
    }

    /**
     * calculate area
     *
     * @param degree
     * @return
     */
    private int calculateArea(float degree) {
        float startDegree = 0;
        float endDegree = 0;
        for (int i = 0; i < scales.length; i++) {
            endDegree += scales[i] * 360;
            if (startDegree < degree && degree < endDegree) return i;
            startDegree = endDegree;
        }
        return -1;
    }
}
